﻿// -------------------------------------------------------------------------
//    @FileName         :    NFCacheDataInsertTransTemplate.h
//    @Author           :    Gao.Yi
//    @Date             :    2025-08-14
//    @Email			:    445267987@qq.com
//    @Module           :    NFCacheDataInsertTransTemplate
//    @Desc             :    缓存数据插入事务模板类
//                           基于模板模式封装缓存数据插入流程，支持不同Protobuf类型的复用
//                           提供插入→查询验证的完整事务流程
//
// -------------------------------------------------------------------------

#pragma once

#include "NFCacheDataGetTrans.h"
#include "NFIServerMessageModule.h"
#include "NFComm/NFObjCommon/NFObject.h"
#include "NFCacheDataInsertTrans.h"

/**
 * @tparam className 具体事务类名（CRTP模式）
 * @tparam pbClass   缓存数据对应的Protobuf类型
 * @tparam classType 共享内存对象类型枚举
 * 
 * @brief 缓存数据插入事务模板类
 * 
 * 基于模板模式封装缓存数据插入的完整流程：
 * 1. 插入操作：向存储服务器发送插入请求
 * 2. 查询验证：插入成功后自动查询验证数据完整性
 * 3. 缓存更新：将查询到的数据添加到缓存中
 * 
 * 使用方式：
 * - 继承此类并实现 AddCacheData() 方法
 * - 通过模板参数指定具体的Protobuf类型
 * - 支持插入→查询验证的完整事务流程
 * 
 * 设计特点：
 * - 使用CRTP模式实现编译时多态
 * - 通过模板参数支持不同Protobuf类型的复用
 * - 提供完整的错误处理和事务管理
 */
template <typename className, typename pbClass, int classType>
class NFCacheDataInsertTransTemplate : public NF_OBJECT_TEMPLATE_MACRO(className, classType, NFCacheDataInsertTrans)
public:
    /**
     * @brief 构造函数，根据共享内存模式进行初始化
     * 
     * 根据共享内存管理器的创建模式选择初始化方式：
     * - EN_OBJ_MODE_INIT：冷启动模式，调用 CreateInit() 进行完整初始化
     * - 其他模式：热启动模式，调用 ResumeInit() 进行恢复初始化
     */
    NFCacheDataInsertTransTemplate()
    {
        if (EN_OBJ_MODE_INIT == NFShmMgr::Instance()->GetCreateMode())
        {
            CreateInit();
        }
        else
        {
            ResumeInit();
        }
    }

    /**
     * @brief 析构函数
     * 
     * 清理资源，由于使用共享内存管理，通常无需特殊处理
     */
    ~NFCacheDataInsertTransTemplate() override
    {

    }

    /**
     * @brief 冷启动创建初始化
     * 
     * 在共享内存冷启动场景下，对新创建的事务对象进行初始化
     * 当前实现为空，如有需要可在此添加初始化逻辑
     * 
     * @return 0 表示成功
     */
    int CreateInit()
    {
        return 0;
    }

    /**
     * @brief 热启动恢复初始化
     * 
     * 在共享内存热启动场景下，从持久化数据恢复事务状态时调用
     * 当前实现为空，如有需要可在此添加恢复逻辑
     * 
     * @return 0 表示成功
     */
    int ResumeInit()
    {
        return 0;
    }

    /**
     * @brief 发起缓存数据插入请求（不带Protobuf消息）
     * 
     * 实现插入→查询验证的完整流程：
     * 1. 保存目标ID和调用原因
     * 2. 构造默认的Protobuf消息对象
     * 3. 设置主键并发送插入请求
     * 4. 插入成功后会自动发起查询验证
     * 
     * @param ullId   目标ID
     * @param iReason 调用原因/场景标识
     * @return 0 表示成功，其他值为错误码
     */
    int InsertCacheDataReq(uint64_t ullId, int iReason) override
    {
        this->m_ullTargetId = ullId;
        this->m_iReason = iReason;
        pbClass stPbClass;
        NFProtobufCommon::SetPrimarykeyFromMessage(&stPbClass, NFCommon::tostr(ullId));
        int iRetCode = FindModule<NFIServerMessageModule>()->SendInsertObjTrans((NF_SERVER_TYPE)this->m_iServerType, ullId, stPbClass, this->m_iTableId, this->GetGlobalId());
        CHECK_ERR(this->m_ullRoleId, iRetCode, "SendInsertObjTrans Failed, roleId:{}", this->m_ullRoleId);
        return 0;
    }

    /**
     * @brief 处理插入操作返回结果
     * 
     * 插入成功后的处理流程：
     * 1. 验证返回结果和错误码
     * 2. 构造查询请求，验证插入的数据完整性
     * 3. 发送查询请求，获取完整的插入数据
     * 
     * @param pRes     存储服务器返回的插入结果
     * @param errCode  错误码
     * @return 0 表示成功，其他值为错误码
     */
    int InsertCacheDataRes(const NFrame::storesvr_insertobj_res* pRes, int32_t errCode) override
    {
        CHECK_NULL(this->m_ullRoleId, pRes);
        if (errCode != 0)
        {
            if (this->m_iTransId <= 0)
            {
                return errCode;
            }

            NFCacheDataGetTrans* pTrans = NFCacheDataGetTrans::GetTrans(this->m_iTransId);
            CHECK_NULL_WF(this->m_ullRoleId, pTrans, "NFCacheDataGetTrans failed, transId:{}", this->m_iTransId);

            // 回调上层事务的结果处理方法
            int iRetCode = pTrans->InsertCacheDataRes(this->m_ullTargetId, this->m_iTableId, this->m_iReason, errCode, nullptr);
            CHECK_ERR_AND_FIN_TRANS(iRetCode, pTrans, "{}::InsertCacheDataRes Failed, m_ullRoleId:{}, m_ullTargetId:{} tableId:{}, reason:{}", pTrans->GetClassName(), this->m_ullRoleId, this->m_ullTargetId, this->m_iTableId, this->m_iReason);

            this->SetFinished(0);
            return 0;
        }

        // 插入成功后，发起查询验证
        pbClass pbCacheData;
        NFProtobufCommon::SetPrimarykeyFromMessage(&pbCacheData, NFCommon::tostr(this->m_ullTargetId));
        int iRetCode = FindModule<NFIServerMessageModule>()->SendSelectObjTrans((NF_SERVER_TYPE)this->m_iServerType, this->m_ullTargetId, pbCacheData, this->m_iTableId, this->GetGlobalId());
        CHECK_ERR(this->m_ullRoleId, iRetCode, "SendSelectObjTrans Failed, ullId:{}", this->m_ullTargetId);
        return 0;
    }

    /**
     * @brief 处理查询操作返回结果
     * 
     * 查询验证成功后的处理流程：
     * 1. 验证返回结果和错误码
     * 2. 解析Protobuf消息数据
     * 3. 调用 LoadCacheDataFromMessage() 将数据添加到缓存
     * 4. 完成事务
     * 
     * @param pRes     存储服务器返回的查询结果
     * @param errCode  错误码
     * @return 0 表示成功，其他值为错误码
     */
    int LoadCacheDataRes(const NFrame::storesvr_selobj_res* pRes, int32_t errCode) override
    {
        CHECK_NULL(this->m_ullRoleId, pRes);
        if (this->m_iTransId <= 0)
        {
            return errCode;
        }

        NFCacheDataGetTrans* pTrans = NFCacheDataGetTrans::GetTrans(this->m_iTransId);
        CHECK_NULL_WF(this->m_ullRoleId, pTrans, "NFCacheDataGetTrans failed, transId:{}", this->m_iTransId);

        if (errCode != 0)
        {
            // 回调上层事务的结果处理方法
            int iRetCode = pTrans->InsertCacheDataRes(this->m_ullTargetId, this->m_iTableId, this->m_iReason, errCode, nullptr);
            CHECK_ERR_AND_FIN_TRANS(iRetCode, pTrans, "{}::InsertCacheDataRes Failed, m_ullRoleId:{}, m_ullTargetId:{} tableId:{}, reason:{}", pTrans->GetClassName(), this->m_ullRoleId, this->m_ullTargetId, this->m_iTableId, this->m_iReason);
        }
        else
        {
            // 解析查询结果
            pbClass pbCacheData;
            bool bRet = pbCacheData.ParseFromString(pRes->record());
            if (!bRet)
            {
                CHECK_ERR(this->m_ullRoleId, -1, "ParseFromString Failed");
            }

            // 回调上层事务的结果处理方法
            int iRetCode = pTrans->InsertCacheDataRes(this->m_ullTargetId, this->m_iTableId, this->m_iReason, errCode, &pbCacheData);
            CHECK_ERR_AND_FIN_TRANS(iRetCode, pTrans, "{}::InsertCacheDataRes Failed, m_ullRoleId:{}, m_ullTargetId:{} tableId:{}, reason:{}", pTrans->GetClassName(), this->m_ullRoleId, this->m_ullTargetId, this->m_iTableId, this->m_iReason);
        }

        this->SetFinished(0);
        return 0;
    }
};